/**
 * 地图服务工具类
 * 处理地图相关API调用，包含错误处理和降级策略
 */

// 默认配置
const DEFAULT_CONFIG = {
    key: 'VXMBZ-ENECT-OP3XY-VFMNE-BWNTO-7RF4N', // 腾讯地图Key
    useCache: true,                            // 是否使用缓存
    cacheDuration: 1000 * 60 * 60,             // 缓存时长（1小时）
    useMockOnFailure: true,                    // 调用失败时是否使用模拟数据
    retryCount: 2,                             // 重试次数
    timeout: 10000                             // 超时时间（毫秒）
};

// 缓存对象
const cache = {
    geocode: {},
    reverseGeocode: {},
    search: {}
};

// 模拟数据
export const MOCK_ADDRESS_DATA = {
    name: '南京师范大学(随园校区)',
    address: '江苏省南京市栖霞区文苑路1号',
    location: {
        lat: 32.089857,
        lng: 118.902066
    },
    pois: [
        {
            id: '1',
            title: '南京师范大学(随园校区)',
            address: '江苏省南京市栖霞区文苑路1号',
            latitude: 32.089857,
            longitude: 118.902066
        },
        {
            id: '2',
            title: '南京师范大学附属中学',
            address: '江苏省南京市鼓楼区宁海路122号',
            latitude: 32.056789,
            longitude: 118.775432
        },
        {
            id: '3',
            title: '南京师范大学(仙林校区)',
            address: '江苏省南京市栖霞区仙林大道1号',
            latitude: 32.113214,
            longitude: 118.928173
        }
    ]
};

/**
 * 处理API错误
 * @param {Object} err - 错误对象
 * @param {Function} reject - Promise的reject函数
 * @param {String} apiName - API名称
 */
const handleApiError = (err, reject, apiName = 'unknown') => {
    console.error(`MapService ${apiName} API error:`, err);
    uni.showToast({
        title: '地图服务暂时不可用',
        icon: 'none'
    });
    reject(err);
};

/**
 * 生成缓存键
 * @param {String} method - 方法名
 * @param {Object} params - 参数
 * @returns {String} - 缓存键
 */
const getCacheKey = (method, params) => {
    return `${method}_${JSON.stringify(params)}`;
};

/**
 * 获取当前位置
 * @param {Object} options - 选项
 * @returns {Promise} - 返回Promise
 */
export const getCurrentLocation = (options = {}) => {
    return new Promise((resolve, reject) => {
        uni.getLocation({
            type: 'gcj02',
            ...options,
            success: (res) => {
                resolve({
                    latitude: res.latitude,
                    longitude: res.longitude
                });
            },
            fail: (err) => {
                console.error('获取位置失败:', err);

                // 如果失败，返回默认位置（南京市中心）
                resolve({
                    latitude: 32.060255,
                    longitude: 118.796877,
                    isDefault: true
                });
            }
        });
    });
};

/**
 * 逆地址解析
 * @param {Number} lat - 纬度
 * @param {Number} lng - 经度
 * @param {Object} userConfig - 用户配置
 * @returns {Promise} - 返回Promise
 */
export const reverseGeocode = (lat, lng, userConfig = {}) => {
    const config = { ...DEFAULT_CONFIG, ...userConfig };
    const cacheKey = getCacheKey('reverseGeocode', { lat, lng });

    // 检查缓存
    if (config.useCache && cache.reverseGeocode[cacheKey] &&
        (Date.now() - cache.reverseGeocode[cacheKey].timestamp < config.cacheDuration)) {
        return Promise.resolve(cache.reverseGeocode[cacheKey].data);
    }

    return new Promise((resolve, reject) => {
        // 记录尝试次数
        let attempts = 0;

        const makeRequest = () => {
            attempts++;

            uni.request({
                url: 'https://apis.map.qq.com/ws/geocoder/v1/',
                data: {
                    location: `${lat},${lng}`,
                    key: config.key,
                    get_poi: 1
                },
                timeout: config.timeout,
                success: (res) => {
                    if (res.statusCode === 200 && res.data && res.data.status === 0) {
                        const result = res.data.result;
                        const data = {
                            address: result.address,
                            name: result.formatted_addresses?.recommend || result.address,
                            pois: result.pois || [],
                            location: {
                                lat,
                                lng
                            }
                        };

                        // 保存到缓存
                        if (config.useCache) {
                            cache.reverseGeocode[cacheKey] = {
                                data,
                                timestamp: Date.now()
                            };
                        }

                        resolve(data);
                    } else {
                        console.warn(`逆地址解析失败 (${attempts}/${config.retryCount + 1}):`, res.data);

                        // 检查是否为API key问题
                        if (res.data && (res.data.status === 121 || res.data.status === 199)) {
                            // API密钥问题，直接使用模拟数据
                            if (config.useMockOnFailure) {
                                resolve(MOCK_ADDRESS_DATA);
                            } else {
                                reject(new Error('地图服务密钥超限'));
                            }
                        } else if (attempts <= config.retryCount) {
                            // 重试
                            setTimeout(makeRequest, 1000);
                        } else if (config.useMockOnFailure) {
                            // 超过重试次数，使用模拟数据
                            resolve(MOCK_ADDRESS_DATA);
                        } else {
                            reject(new Error(res.data.message || '逆地址解析失败'));
                        }
                    }
                },
                fail: (err) => {
                    if (attempts <= config.retryCount) {
                        // 重试
                        setTimeout(makeRequest, 1000);
                    } else if (config.useMockOnFailure) {
                        // 超过重试次数，使用模拟数据
                        resolve(MOCK_ADDRESS_DATA);
                    } else {
                        handleApiError(err, reject, 'reverseGeocode');
                    }
                }
            });
        };

        makeRequest();
    });
};

/**
 * 地点搜索
 * @param {String} keyword - 关键字
 * @param {Object} userConfig - 用户配置
 * @returns {Promise} - 返回Promise
 */
export const searchPOI = (keyword, userConfig = {}) => {
    const config = { ...DEFAULT_CONFIG, ...userConfig };
    const cacheKey = getCacheKey('search', { keyword });

    // 检查缓存
    if (config.useCache && cache.search[cacheKey] &&
        (Date.now() - cache.search[cacheKey].timestamp < config.cacheDuration)) {
        return Promise.resolve(cache.search[cacheKey].data);
    }

    return new Promise((resolve, reject) => {
        if (!keyword.trim()) {
            resolve([]);
            return;
        }

        // 记录尝试次数
        let attempts = 0;

        const makeRequest = () => {
            attempts++;

            uni.request({
                url: 'https://apis.map.qq.com/ws/place/v1/search',
                data: {
                    keyword: keyword,
                    key: config.key,
                    region: userConfig.region || ''
                },
                timeout: config.timeout,
                success: (res) => {
                    if (res.statusCode === 200 && res.data && res.data.status === 0) {
                        const data = res.data.data || [];

                        // 保存到缓存
                        if (config.useCache) {
                            cache.search[cacheKey] = {
                                data,
                                timestamp: Date.now()
                            };
                        }

                        resolve(data);
                    } else {
                        console.warn(`搜索POI失败 (${attempts}/${config.retryCount + 1}):`, res.data);

                        // 检查是否为API key问题
                        if (res.data && (res.data.status === 121 || res.data.status === 199)) {
                            // API密钥问题，直接使用模拟数据
                            if (config.useMockOnFailure) {
                                resolve(MOCK_ADDRESS_DATA.pois);
                            } else {
                                reject(new Error('地图服务密钥超限'));
                            }
                        } else if (attempts <= config.retryCount) {
                            // 重试
                            setTimeout(makeRequest, 1000);
                        } else if (config.useMockOnFailure) {
                            // 超过重试次数，使用模拟数据
                            resolve(MOCK_ADDRESS_DATA.pois);
                        } else {
                            reject(new Error(res.data.message || '搜索POI失败'));
                        }
                    }
                },
                fail: (err) => {
                    if (attempts <= config.retryCount) {
                        // 重试
                        setTimeout(makeRequest, 1000);
                    } else if (config.useMockOnFailure) {
                        // 超过重试次数，使用模拟数据
                        resolve(MOCK_ADDRESS_DATA.pois);
                    } else {
                        handleApiError(err, reject, 'searchPOI');
                    }
                }
            });
        };

        makeRequest();
    });
};

/**
 * 获取静态地图URL
 * 当动态地图无法加载时，可以使用静态地图作为回退
 * @param {Number} lat - 纬度
 * @param {Number} lng - 经度
 * @param {Object} options - 参数选项
 * @returns {String} - 静态地图URL
 */
export const getStaticMapUrl = (lat, lng, options = {}) => {
    const {
        width = 600,
        height = 300,
        zoom = 16,
        markers = true,
        key = DEFAULT_CONFIG.key
    } = options;

    // 构建基本URL
    let url = `https://apis.map.qq.com/ws/staticmap/v2/?center=${lat},${lng}&zoom=${zoom}&size=${width}*${height}&key=${key}`;

    // 如果需要标记
    if (markers) {
        url += `&markers=size:large|color:0xFFCC00|${lat},${lng}`;
    }

    return url;
};

/**
 * 预加载地图瓦片
 * 尝试通过预加载关键瓦片来减少加载错误
 * @param {Number} lat - 纬度
 * @param {Number} lng - 经度
 * @param {Number} zoom - 缩放级别
 */
export const preloadMapTiles = (lat, lng, zoom = 16) => {
    const tileCoords = latLngToTileCoords(lat, lng, zoom);
    const tileUrls = [];

    // 生成周围9个瓦片的URL
    for (let i = -1; i <= 1; i++) {
        for (let j = -1; j <= 1; j++) {
            const x = tileCoords.x + i;
            const y = tileCoords.y + j;
            tileUrls.push(getTileUrl(x, y, zoom));
        }
    }

    // 预加载瓦片
    tileUrls.forEach(url => {
        uni.request({
            url,
            timeout: 5000,
            success: () => { },
            fail: () => { }
        });
    });
};

/**
 * 将经纬度转换为瓦片坐标
 * @param {Number} lat - 纬度
 * @param {Number} lng - 经度
 * @param {Number} zoom - 缩放级别
 * @returns {Object} - 瓦片坐标 {x, y}
 */
const latLngToTileCoords = (lat, lng, zoom) => {
    const n = Math.pow(2, zoom);
    const x = Math.floor((lng + 180) / 360 * n);
    const latRad = lat * Math.PI / 180;
    const y = Math.floor((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * n);
    return { x, y };
};

/**
 * 获取瓦片URL
 * @param {Number} x - 瓦片X坐标
 * @param {Number} y - 瓦片Y坐标
 * @param {Number} zoom - 缩放级别
 * @returns {String} - 瓦片URL
 */
const getTileUrl = (x, y, zoom) => {
    return `https://rt2.map.gtimg.com/tile?z=${zoom}&x=${x}&y=${y}&styleid=1&version=1888`;
};

/**
 * 清除缓存
 * @param {String} type - 缓存类型，可选值：'all', 'geocode', 'reverseGeocode', 'search'
 */
export const clearCache = (type = 'all') => {
    if (type === 'all') {
        Object.keys(cache).forEach(key => {
            cache[key] = {};
        });
    } else if (cache[type]) {
        cache[type] = {};
    }
};

// 默认地图中心点（南宁市中心）
const DEFAULT_CENTER = {
    latitude: 22.817,
    longitude: 108.366
};

/**
 * 计算两点之间的距离（米）
 * @param {Object} point1 - 第一个点 {latitude, longitude}
 * @param {Object} point2 - 第二个点 {latitude, longitude}
 * @returns {Number} 距离，单位米
 */
const calculateDistance = (point1, point2) => {
    if (!point1 || !point2) return 0;

    const lat1 = point1.latitude;
    const lng1 = point1.longitude;
    const lat2 = point2.latitude;
    const lng2 = point2.longitude;

    const rad = Math.PI / 180;
    const radLat1 = lat1 * rad;
    const radLat2 = lat2 * rad;
    const a = radLat1 - radLat2;
    const b = lng1 * rad - lng2 * rad;

    const s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
        Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));

    return s * 6378137; // 地球半径（米）
};

/**
 * 格式化距离显示
 * @param {Number} distance - 距离（米）
 * @returns {String} 格式化后的距离
 */
const formatDistance = (distance) => {
    if (distance < 1000) {
        return Math.round(distance) + '米';
    } else {
        return (distance / 1000).toFixed(1) + '公里';
    }
};

/**
 * 打开导航
 * @param {Object} destination - 目的地 {latitude, longitude, name}
 */
const openNavigation = (destination) => {
    if (!destination || !destination.latitude || !destination.longitude) {
        uni.showToast({
            title: '无法获取目的地位置',
            icon: 'none'
        });
        return;
    }

    uni.openLocation({
        latitude: parseFloat(destination.latitude),
        longitude: parseFloat(destination.longitude),
        name: destination.name || '目的地',
        address: destination.address || '',
        success: () => {
            console.log('打开导航成功');
        },
        fail: (err) => {
            console.error('打开导航失败:', err);
            uni.showToast({
                title: '打开导航失败',
                icon: 'none'
            });
        }
    });
};

export default {
    getCurrentLocation,
    reverseGeocode,
    searchPOI,
    clearCache,
    MOCK_ADDRESS_DATA,
    getStaticMapUrl,
    preloadMapTiles,
    DEFAULT_CENTER,
    calculateDistance,
    formatDistance,
    openNavigation
}; 